# coding:utf-8
import time

from selenium.common import NoSuchElementException, ElementClickInterceptedException, InvalidElementStateException
from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.webdriver import WebDriver
from tqdm import tqdm

from conf.config import logger, config


class NewbingBot(object):
    def __init__(self, browser, *args, **kwargs):
        super(NewbingBot, self).__init__(*args, **kwargs)
        self.browser: "WebDriver" = browser

        self.browser.maximize_window()

        logger.info(f"打开https://www.bing.com/")
        self.browser.get(url="https://www.bing.com/")

        time.sleep(5)

        logger.info(f"点击登录，弹出登录窗口")
        self.browser.find_element(by=By.XPATH, value='//span[@id="id_s"]').click()

        time.sleep(5)

        logger.info(f"输入账号名")
        try:
            ele_user = self.browser.find_element(by=By.XPATH, value='//input[@name="loginfmt"]')
        except NoSuchElementException:
            logger.warning(f"再次点击登录，弹出登录窗口")
            self.browser.find_element(by=By.XPATH, value='//span[@id="id_s"]').click()
            time.sleep(5)
            ele_user = self.browser.find_element(by=By.XPATH, value='//input[@name="loginfmt"]')

        ele_user.clear()
        ele_user.send_keys(config.get('bing_username'))
        ele_user.send_keys(Keys.ENTER)

        time.sleep(5)

        logger.info(f"输入密码")
        try:  # 可能出现弹窗：此电子邮件似乎已用于多个Microsoft账号，可选工作账号或个人账号
            ele_passwd = self.browser.find_element(by=By.XPATH, value='//input[@name="passwd"]')
        except NoSuchElementException:
            self.browser.find_element(by=By.XPATH, value='//div[text()="个人帐户"]').click()
            time.sleep(5)
            ele_passwd = self.browser.find_element(by=By.XPATH, value='//input[@name="passwd"]')
        ele_passwd.clear()
        ele_passwd.send_keys(config.get('bing_passwd'))
        ele_passwd.send_keys(Keys.ENTER)

        time.sleep(5)

        logger.info(f"保持登录状态，选择默认值：是")
        ActionChains(self.browser).send_keys(Keys.ENTER).perform()

        time.sleep(5)

        logger.info(f"点击聊天，进入聊天模式")
        try:
            self.browser.find_element(by=By.XPATH, value='//a[text()="聊天"]').click()
        except ElementClickInterceptedException:
            logger.info(f"刷新一下，再次点击聊天，进入聊天模式")
            self.browser.refresh()
            time.sleep(5)
            self.browser.find_element(by=By.XPATH, value='//a[text()="聊天"]').click()

        if config.get("bing_switch_to_more_creative"):
            time.sleep(5)

            logger.info(f"点击更多有创造力，切换温度值T到更高")
            shadow_host1 = self.browser.find_element(by=By.CLASS_NAME, value='cib-serp-main')
            # logger.info(f"{shadow_host1.get_attribute('class')}")
            shadow_root1 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host1)

            shadow_host2 = shadow_root1.find_element(by=By.ID, value='cib-conversation-main')
            # logger.info(f"{shadow_host2.get_attribute('id')}")
            shadow_root2 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host2)

            shadow_host3 = shadow_root2.find_element(by=By.CSS_SELECTOR, value='cib-welcome-container')
            # logger.info(f"{shadow_host3.get_attribute('product')}")
            shadow_root3 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host3)

            shadow_host4 = shadow_root3.find_element(by=By.CSS_SELECTOR, value='cib-tone-selector')
            # logger.info(f"{shadow_host4.get_attribute('style')}")
            shadow_root4 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host4)

            try:
                button_creative = shadow_root4.find_element(by=By.CLASS_NAME, value='tone-creative')
                button_creative.click()
            except ElementClickInterceptedException:
                logger.warning(f"元素不可点击，再查找一次")
                button_creative = shadow_root4.find_element(by=By.CLASS_NAME, value='tone-creative')
                button_creative.click()

        time.sleep(5)

    def reply(self, query):
        content, content_footer = self.reply_html(query)
        return content, content_footer

    def reply_html(self, query):
        """
        获取newbing的响应内容
        :param query: 要查询内容
        :return: 响应的内容，包含正文和引用源
        """
        logger.info(f"输入要查询的内容：{query}")
        shadow_host20 = self.browser.find_element(by=By.CLASS_NAME, value='cib-serp-main')
        shadow_root20 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host20)

        shadow_host21 = shadow_root20.find_element(by=By.ID, value='cib-action-bar-main')
        shadow_root21 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host21)

        try:
            ele_search_box = shadow_root21.find_element(by=By.ID, value='searchbox')
            ele_search_box.clear()
            ele_search_box.send_keys(f"{query}")
            ele_search_box.send_keys(Keys.ENTER)
        except InvalidElementStateException:
            logger.warning(f"搜索框无法点击，重试")
            time.sleep(5)
            ele_search_box = shadow_root21.find_element(by=By.ID, value='searchbox')
            ele_search_box.clear()
            ele_search_box.send_keys(f"{query}")
            ele_search_box.send_keys(Keys.ENTER)

        # 等待生成响应  # TODO 显性等待貌似不可用
        logger.info(f"生成响应中...")
        time.sleep(5)
        while True:
            shadow_host30 = self.browser.find_element(by=By.CLASS_NAME, value='cib-serp-main')
            shadow_root30 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host30)

            shadow_host31 = shadow_root30.find_element(by=By.ID, value='cib-action-bar-main')
            shadow_root31 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host31)

            shadow_host32 = shadow_root31.find_element(by=By.CSS_SELECTOR, value='cib-typing-indicator')
            shadow_root32 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host32)

            shadow_host33 = shadow_root32.find_elements(by=By.CSS_SELECTOR, value='button#stop-responding-button[disabled=""]')  # button的id为stop-responding-button，且有disabled属性，属性值为空

            if shadow_host33:
                logger.info(f"响应按钮已消失，跳出循环")
                break
            else:
                time.sleep(config.get("wait_seconds_of_newbing_response"))

        # 响应框的顶部文本
        shadow_host40 = self.browser.find_element(by=By.CLASS_NAME, value='cib-serp-main')
        shadow_root40 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host40)

        shadow_host41 = shadow_root40.find_element(by=By.ID, value='cib-conversation-main')
        shadow_root41 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host41)

        shadow_host42 = shadow_root41.find_elements(by=By.CSS_SELECTOR, value='cib-chat-turn')[-1]  # 最后的一次会话轮次
        shadow_root42 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host42)

        shadow_host43 = shadow_root42.find_element(by=By.CLASS_NAME, value='response-message-group')
        shadow_root43 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host43)

        # bing联网时，取的是[-2]，没联网时取的是[-1]。像简单的加减是不需要联网的
        try:
            shadow_host44 = shadow_root43.find_elements(by=By.CSS_SELECTOR, value='cib-message')[-2]
            shadow_root44 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host44)
            ele_content = shadow_root44.find_element(by=By.CLASS_NAME, value='ac-textBlock')
        except(IndexError, NoSuchElementException):
            logger.warning(f"本次给的答案可能没联网")
            shadow_host44 = shadow_root43.find_elements(by=By.CSS_SELECTOR, value='cib-message')[-1]
            shadow_root44 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host44)
            ele_content = shadow_root44.find_element(by=By.CLASS_NAME, value='ac-textBlock')
        content = f"{ele_content.get_attribute('innerHTML')}"
        logger.info(content)

        # 响应框的底部文本
        shadow_host45 = shadow_root44.find_element(by=By.CSS_SELECTOR, value='cib-message-attributions')
        shadow_root45 = self.browser.execute_script('return arguments[0].shadowRoot', shadow_host45)

        ele_footer_content = shadow_root45.find_element(by=By.CLASS_NAME, value='attribution-container')
        content_footer = f"{ele_footer_content.get_attribute('innerHTML')}"
        logger.info(content_footer)

        return content, content_footer


def main():
    pass


if __name__ == '__main__':
    main()
